package word.parser;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class WordEleFactory {
    private static final Pattern IDENT_PATTERN = Pattern.compile("^([\\w]+)(.*)$");
    private static final Pattern INTTK_PATTERN = Pattern.compile("^([\\d]+)(.*)$");
    private static final Pattern NOTE_END_PATTERN = Pattern.compile("\\*/(.*)");
    private static final Pattern SPACE_PATTERN = Pattern.compile("[\\s]*(\\S.*)");
    private static final HashMap<String, WordElement.WordType> DISTINGUISH_MAP = new HashMap<>();
    private boolean isNote = false;

    static {
        // DISTINGUISH_MAP.put("Ident", WordElement.WordType.IDENFR);
        DISTINGUISH_MAP.put("!", WordElement.WordType.NOT);
        DISTINGUISH_MAP.put("*", WordElement.WordType.MULT);
        DISTINGUISH_MAP.put("=", WordElement.WordType.ASSIGN);
        // DISTINGUISH_MAP.put("IntConst", WordElement.WordType.INTCON);
        DISTINGUISH_MAP.put("&&", WordElement.WordType.AND);
        DISTINGUISH_MAP.put("/", WordElement.WordType.DIV);
        DISTINGUISH_MAP.put(";", WordElement.WordType.SEMICN);
        // DISTINGUISH_MAP.put("FormatString", WordElement.WordType.STRCON);
        DISTINGUISH_MAP.put("||", WordElement.WordType.OR);
        DISTINGUISH_MAP.put("%", WordElement.WordType.MOD);
        DISTINGUISH_MAP.put(",", WordElement.WordType.COMMA);
        DISTINGUISH_MAP.put("main", WordElement.WordType.MAINTK);
        DISTINGUISH_MAP.put("while", WordElement.WordType.WHILETK);
        DISTINGUISH_MAP.put("<", WordElement.WordType.LSS);
        DISTINGUISH_MAP.put("(", WordElement.WordType.LPARENT);
        DISTINGUISH_MAP.put("const", WordElement.WordType.CONSTTK);
        DISTINGUISH_MAP.put("getint", WordElement.WordType.GETINTTK);
        DISTINGUISH_MAP.put("<=", WordElement.WordType.LEQ);
        DISTINGUISH_MAP.put(")", WordElement.WordType.RPARENT);
        DISTINGUISH_MAP.put("int", WordElement.WordType.INTTK);
        DISTINGUISH_MAP.put("printf", WordElement.WordType.PRINTFTK);
        DISTINGUISH_MAP.put(">", WordElement.WordType.GRE);
        DISTINGUISH_MAP.put("[", WordElement.WordType.LBRACK);
        DISTINGUISH_MAP.put("break", WordElement.WordType.BREAKTK);
        DISTINGUISH_MAP.put("return", WordElement.WordType.RETURNTK);
        DISTINGUISH_MAP.put(">=", WordElement.WordType.GEQ);
        DISTINGUISH_MAP.put("]", WordElement.WordType.RBRACK);
        DISTINGUISH_MAP.put("continue", WordElement.WordType.CONTINUETK);
        DISTINGUISH_MAP.put("+", WordElement.WordType.PLUS);
        DISTINGUISH_MAP.put("==", WordElement.WordType.EQL);
        DISTINGUISH_MAP.put("{", WordElement.WordType.LBRACE);
        DISTINGUISH_MAP.put("if", WordElement.WordType.IFTK);
        DISTINGUISH_MAP.put("-", WordElement.WordType.MINU);
        DISTINGUISH_MAP.put("!=", WordElement.WordType.NEQ);
        DISTINGUISH_MAP.put("}", WordElement.WordType.RBRACE);
        DISTINGUISH_MAP.put("else", WordElement.WordType.ELSETK);
        DISTINGUISH_MAP.put("void", WordElement.WordType.VOIDTK);
    }

    public ArrayList<WordElement> buildElements(String wordIn, int line) {
        ArrayList<WordElement> elements = new ArrayList<>();
        boolean isFormatString = false;
        String word = wordIn;
        while (true) {

            if (isNote) {
                Matcher noteMatcher = NOTE_END_PATTERN.matcher(word);
                boolean hasMatch = noteMatcher.find();
                if (hasMatch) {
                    isNote = false;
                    word = noteMatcher.group(1);
                    continue;
                }
                break;
            }
            if (isFormatString) {
                Pattern formatStringPatter = Pattern.compile("([^\"]*\")(.*)");
                Matcher formatStringMatcher = formatStringPatter.matcher(word);
                if (!formatStringMatcher.find()) {
                    break;
                }
                word = formatStringMatcher.group(2);
                String formatString = "\"" + formatStringMatcher.group(1);
                elements.add(new WordElement(formatString, WordElement.WordType.STRCON, line));
                isFormatString = false;
                continue;
            }
            // System.out.println(word);
            Matcher spaceMatcher = SPACE_PATTERN.matcher(word);
            if (!spaceMatcher.find()) {
                break;
            }
            word = spaceMatcher.group(1);
            // System.out.println(word);

            String ident = "";
            String last;
            Matcher matcher = IDENT_PATTERN.matcher(word);
            if (matcher.find()) {
                ident = matcher.group(1);
                last = matcher.group(2);
            } else {
                last = word;
            }

            if (!ident.isEmpty()) {
                WordElement.WordType type = DISTINGUISH_MAP.get(ident);
                if (type == null) {
                    type = WordElement.WordType.INTCON;
                    Matcher intMatcher = INTTK_PATTERN.matcher(ident);
                    if (intMatcher.find()) {
                        String number = intMatcher.group(1);
                        String clearIdent = intMatcher.group(2);
                        if (!number.isEmpty()) {
                            elements.add(new WordElement(number, WordElement.WordType.INTCON, line));
                        }
                        if (!clearIdent.isEmpty()) {
                            elements.add(new WordElement(clearIdent, WordElement.WordType.IDENFR, line));
                        }
                    } else {
                        elements.add(new WordElement(ident, WordElement.WordType.IDENFR, line));
                    }
                } else {
                    elements.add(new WordElement(ident, type, line));
                }
            } else if (!last.isEmpty()) {
                int noteJudge = noteJudge(last);
                if (noteJudge == 2) {
                    break;
                }
                if (noteJudge == 1) {
                    isNote = true;
                    word = last.substring(2);
                    continue;
                }

                if (word.charAt(0) == '\"') {
                    word = word.substring(1);
                    isFormatString = true;
                    continue;
                }

                String tmpSign = "";
                WordElement.WordType type = null;
                int le = 0;
                if (word.length() > 1) {
                    tmpSign = "" + word.charAt(0) + word.charAt(1);
                    type = DISTINGUISH_MAP.get(tmpSign);
                    le = 2;
                }
                if (type == null) {
                    tmpSign = "" + word.charAt(0);
                    le = 1;
                    type = DISTINGUISH_MAP.get(tmpSign);
                }
                elements.add(new WordElement(tmpSign, type, line));
                last = last.substring(le);
            }
            word = last;
            if (last.isEmpty()) {
                break;
            }
        }
        return elements;
    }

    private int noteJudge(String s) {
        if (s.charAt(0) == '/' && s.charAt(1) == '*') {
            return 1;
        }
        if (s.charAt(0) == '/' && s.charAt(1) == '/') {
            return 2;
        }
        return 0;
    }

}
